package cn.toma.common.tencent;


import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.exception.CosServiceException;
import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.PutObjectResult;
import com.qcloud.cos.model.UploadResult;
import com.qcloud.cos.region.Region;
import com.qcloud.cos.transfer.TransferManager;
import com.qcloud.cos.transfer.Upload;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author zqx
 * @version 1.0.0
 * @ClassName CosUploadUtil.java
 * @Description 腾讯云COS 上传文件工具类
 * @createTime 2019年09月12日 09:43:00
 */
@Data
@Slf4j
@Component
@ConfigurationProperties(prefix = "tencent.cos")
public class UploadCosUtil
{

	private String appId;
	private String secretId;
	private String secretKey;
	private String region;
	private String bucketName;
	private String bucketUrl;
	private String domainUrl;

	/**
	 * 获取客户端
	 * 1.初始化用户身份信息(secretId, secretKey，可在腾讯云后台中的API密钥管理中查看！
	 * 2.初始化region
	 *
	 * @return
	 */
	private COSClient getCOSClient()
	{
		return new COSClient(new BasicCOSCredentials(secretId, secretKey), new ClientConfig(new Region(region)));
	}


	/**
	 * 2 设置bucket的区域, COS地域的简称请参照 https://cloud.tencent.com/document/product/436/6224 根据自己创建的存储桶选择地区
	 */


	/**
	 * 简单文件上传, 最大支持 5 GB, 适用于小文件上传, 建议 20 M 以下的文件使用该接口
	 *
	 * @param localFile
	 * @throws CosClientException
	 * @throws CosServiceException
	 */
	public void uploadfile(File localFile) throws CosClientException, CosServiceException
	{
		// 生成cos客户端
		COSClient cosclient = getCOSClient();
		try {
			// 指定要上传到 COS 上的路径
			String key = localFile.getName();

			PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, localFile);

			PutObjectResult putObjectResult = cosclient.putObject(putObjectRequest);
			System.out.println(putObjectResult);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 关闭客户端(关闭后台线程)
			cosclient.shutdown();
		}

	}

	/**
	 * MultipartFile 文件上传
	 *
	 * @param file    MultipartFile
	 * @param cosFile 指定文件夹名称
	 * @throws CosClientException
	 * @throws CosServiceException
	 */
	public String uploadfile(MultipartFile file, String cosFile) throws CosClientException, CosServiceException
	{
		// 生成cos客户端
		COSClient cosclient = getCOSClient();
		try {
			String fileName = file.getOriginalFilename();
			// 指定要上传到 COS 上的路径
			String key = UUID.randomUUID() + "." + fileName.substring(fileName.lastIndexOf(".") + 1);

			if (!StringUtils.isEmpty(cosFile)) {
				key = cosFile + "/" + key;
			}
			PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, file.getInputStream(), new ObjectMetadata());
			PutObjectResult putObjectResult = cosclient.putObject(putObjectRequest);

			String fileUrl = getFileUrl(cosclient, key);

			return fileUrl;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 关闭客户端(关闭后台线程)
			cosclient.shutdown();
		}
		return null;
	}

	/**
	 * 高级Api 上传文件, 根据文件大小自动选择简单上传或者分块上传。
	 *
	 * @param file    MultipartFile
	 * @param cosFile 指定文件名称
	 */
	public String uploadTransferFile(MultipartFile file, String cosFile)
	{

		// 3 生成cos客户端
		COSClient cosclient = getCOSClient();

		ExecutorService threadPool = Executors.newFixedThreadPool(32);
		/**
		 * 传入一个threadpool, 若不传入线程池, 默认TransferManager中会生成一个单线程的线程池。
		 */
		TransferManager transferManager = new TransferManager(cosclient, threadPool);
		try {
			// 指定要上传到 COS 上的路径
			String fileName = file.getOriginalFilename();
			String key = UUID.randomUUID() + "." + fileName.substring(fileName.lastIndexOf(".") + 1);
			if (!StringUtils.isEmpty(cosFile)) {
				key = cosFile + "/" + key;
			}
			PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, file.getInputStream(), new ObjectMetadata());
			// 返回一个异步结果Upload, 可同步的调用waitForUploadResult等待upload结束, 成功返回UploadResult, 失败抛出异常.
			Upload upload = transferManager.upload(putObjectRequest);
			UploadResult uploadResult = upload.waitForUploadResult();
			return getFileUrl(cosclient, key);
		} catch (CosServiceException | InterruptedException | IOException e) {
			e.printStackTrace();
		} finally {
			transferManager.shutdownNow();
			cosclient.shutdown();
		}
		return null;

	}


	/**
	 * 获取文件地址
	 *
	 * @param cosclient 客户端链接
	 * @param key       文件名
	 * @return url
	 */
	public String getFileUrl(COSClient cosclient, String key)
	{
		Date expiration = new Date(System.currentTimeMillis() + 60 * 60 * 1000);
		URL url = cosclient.generatePresignedUrl(bucketName, key, expiration);
		String tempUrl = url.toString();
		// 自定义域名替换
		String temp = tempUrl.replaceAll(bucketUrl, domainUrl);
		temp = StringUtils.substringBefore(temp, "?");
		log.debug("upload cos : {}", temp);
		return temp;
	}

	/**
	 * 删除文件
	 *
	 * @param key 文件名称
	 */
	public void deletefile(String key) throws CosClientException, CosServiceException
	{
		// 生成cos客户端
		COSClient cosclient = getCOSClient();
		// 指定要删除的 bucket 和路径
		cosclient.deleteObject(bucketName, key);
		// 关闭客户端(关闭后台线程)
		cosclient.shutdown();
	}

}
